package model

import (
	"strings"
	"sync"
	"toyota-server/init/global"
	j_log "toyota-server/init/j-log"
	"toyota-server/utils/tools"
)

// PointItem 数据点位信息
type PointItem struct {
	Module   uint8   `json:"module"`
	Title    string  `json:"title"`
	Addr     string  `json:"addr"`
	Value    float64 `json:"value"`
	DataType string  `json:"data_type"`
	//CreateTime *string `json:"create_time" gorm:"column:create_time"`
}

type Alert struct {
	ID           int     `json:"id" gorm:"column:id"`
	Module       uint8   `json:"module" gorm:"column:module"`
	Title        string  `json:"title" gorm:"column:title"`
	Addr         string  `json:"addr" gorm:"column:addr"`
	Value        float64 `json:"value" gorm:"column:value"`
	CreateTime   *string `json:"create_time" gorm:"column:create_time"`
	IsRecovery   uint8   `json:"is_recovery" gorm:"column:is_recovery"`
	RecoveryTime *string `json:"recovery_time" gorm:"column:recovery_time"`
}

func (t *Alert) TableName() string {
	return "alert"
}

type AlertDataMapStu struct {
	ModuleID     int               `json:"module_id"`   // 模块ID 1.SS离心机 2.FC离心机 3.SS热泵机组 4.FC热泵机组
	ModuleName   string            `json:"module_name"` // 模块名称
	M            map[string]*Alert `json:"-"`           // 内存报警信息
	PointQueue   chan []*PointItem `json:"-"`           // 实时数据
	AlertADDRMap map[string]bool   `json:"-"`           // 需要判断报警的点位地址
	sync.RWMutex `json:"-"`
}

func (m *AlertDataMapStu) Set(key string, v *Alert) {
	m.Lock()
	defer m.Unlock()
	m.M[key] = v
}
func (m *AlertDataMapStu) Get(key string) (v *Alert, ok bool) {
	m.RLock()
	defer m.RUnlock()
	v, ok = m.M[key]
	if !ok {
		v = &Alert{}
	}
	return
}
func (m *AlertDataMapStu) Delete(key string) {
	m.Lock()
	defer m.Unlock()
	delete(m.M, key)
}
func (m *AlertDataMapStu) AlertHandle() {
	for points := range m.PointQueue {
		alertList := make([]*Alert, 0)
		for _, point := range points {
			if !m.AlertADDRMap[point.Addr] {
				continue
			}
			now := tools.GetNow()
			alert := &Alert{}
			alert.Title = point.Title
			alert.Addr = point.Addr
			alert.Value = point.Value
			alert.Module = uint8(m.ModuleID)
			old, ok := m.Get(point.Addr)
			if ok {
				if point.Value == old.Value {
					continue
				}
				if point.Value == 0 {
					//  已恢复
					alert.CreateTime = old.CreateTime
					alert.RecoveryTime = &now
					alert.IsRecovery = 1
					//j_log.LogInfo([]interface{}{fmt.Sprintf("报警恢复 addr=%s, old.ID=%v", old.Addr, old.ID)})
					if DB != nil {
						err := DB.Model(&Alert{}).Where("id = ?", old.ID).Select("is_recovery", "recovery_time").Updates(alert).Error
						if err != nil {
							j_log.LogError([]interface{}{"sql error updates", err.Error()})
						}
					}
					alertList = append(alertList, alert)
					m.Delete(point.Addr)
				} else {
					alert.CreateTime = &now
					//j_log.LogInfo([]interface{}{fmt.Sprintf("新增报警 addr=%s", alert.Addr)})
					if DB != nil {
						err := DB.Create(alert).Error
						if err != nil {
							j_log.LogError([]interface{}{"sql error create", err.Error()})
						}
					}
					alertList = append(alertList, alert)
					m.Set(alert.Addr, alert)
				}
			} else {
				if point.Value == 1 {
					alert.CreateTime = &now
					//j_log.LogInfo([]interface{}{fmt.Sprintf("新增报警 addr=%s", alert.Addr)})
					if DB != nil {
						err := DB.Create(alert).Error
						if err != nil {
							j_log.LogError([]interface{}{"sql error create", err.Error()})
						}
					}

					alertList = append(alertList, alert)
					m.Set(alert.Addr, alert)
				}
			}
		}
		//if len(alertList) > 0 {
		//	jsonB, _ := json.Marshal(&alertList)
		//	_ = socket.WSClientMap.BroadcastMessage(m.ModuleID+100, m.ModuleName, string(jsonB))
		//}
	}
}

func NewAlertDataMap(key string) *AlertDataMapStu {
	var moduleName string
	var moduleID int
	switch key {
	case "ss_centrifuge":
		moduleName = "centrifuge"
		moduleID = 1
	case "fc_centrifuge":
		moduleName = "centrifuge"
		moduleID = 2
	case "ss_mcquay":
		moduleName = "mcquay"
		moduleID = 3
	case "fc_mcquay":
		moduleName = "mcquay"
		moduleID = 4
	}
	return &AlertDataMapStu{
		ModuleID:     moduleID,
		ModuleName:   moduleName,
		M:            make(map[string]*Alert),
		PointQueue:   make(chan []*PointItem, 10000),
		AlertADDRMap: GenAlertADDRMap(key),
	}
}
func GenAlertADDRMap(name string) (m map[string]bool) {
	m = make(map[string]bool)
	str := global.AppConfig.Section(name).Key("alert_addrs").String()
	arr := strings.Split(str, ",")
	for _, v := range arr {
		if v != "" {
			m[v] = true
		}
	}
	return
}
